import { useCallback, useEffect, useMemo, useState, type ReactNode } from 'react';
import { config } from '../config';
import {
  AuthContext,
  type AuthContextValue,
  type AuthStatus,
  type UserProfile,
} from '../contexts/AuthContext';

const buildReturnUrl = () => encodeURIComponent(window.location.href);

const getBffUrl = (path: string) => {
  const trimmed = config.BFF_BASE_URL.replace(/\/$/, '');
  return `${trimmed}${path.startsWith('/') ? path : `/${path}`}`;
};

export const AuthProvider = ({ children }: { children: ReactNode }) => {
  const [status, setStatus] = useState<AuthStatus>('loading');
  const [user, setUser] = useState<UserProfile | null>(null);
  const [error, setError] = useState<string | null>(null);

  const fetchProfile = useCallback(async () => {
    setStatus('loading');
    setError(null);
    try {
      const response = await fetch(getBffUrl('/api/me'), {
        credentials: 'include',
        redirect: 'manual',
      });

      if (response.type === 'opaqueredirect' || response.status === 0) {
        setUser(null);
        setStatus('signedOut');
        return;
      }

      if (response.status === 401) {
        setUser(null);
        setStatus('signedOut');
        return;
      }

      if (!response.ok) {
        throw new Error(await response.text());
      }

      const profile = (await response.json()) as UserProfile;
      const resolvedSub =
        profile.sub ??
        profile.claims?.find((claim) => {
          const type = claim.type?.toLowerCase() ?? '';
          return type.endsWith('nameidentifier') || type === 'sub';
        })?.value;

      setUser(resolvedSub ? { ...profile, sub: resolvedSub } : profile);
      setStatus('signedIn');
    } catch (err) {
      setError(err instanceof Error ? err.message : 'Authentication failed');
      setUser(null);
      setStatus('signedOut');
    }
  }, []);

  useEffect(() => {
    void fetchProfile();
  }, [fetchProfile]);

  const signIn = useCallback(() => {
    window.location.href = `${getBffUrl('/login')}?returnUrl=${buildReturnUrl()}`;
  }, []);

  const signOut = useCallback(() => {
    window.location.href = `${getBffUrl('/logout')}?returnUrl=${buildReturnUrl()}`;
  }, []);

  const value = useMemo<AuthContextValue>(
    () => ({
      status,
      user,
      error,
      isAuthenticated: status === 'signedIn',
      refresh: fetchProfile,
      signIn,
      signOut,
    }),
    [status, user, error, fetchProfile, signIn, signOut],
  );

  return <AuthContext.Provider value={value}>{children}</AuthContext.Provider>;
};
